﻿using AutoMapper;
using AutoMapper.Internal.Mappers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Travel.CommonUtil;
using Travel.CommonUtil.RedisUtil;
using Travel.CommonUtil.Snowflake;
using Travel.Data;
using Travel.Data.Consts;
using Travel.Data.Dtos;
using Travel.Data.Dtos.TravelBusiness;
using Travel.Data.Entity;
using Travel.Data.Enums;
using Travel.Data.Inputs;

namespace Travel.Service.User.Impl
{
    public class UserService : ServiceBase, IUserService
    {
        private readonly HappyTravelContext _context;
        private readonly IMapper _mapper;
        private readonly IdWorker _idWorker;
        private readonly IConfiguration _configuration;
        private readonly ILogger<UserService> _logger;
        public UserService(HappyTravelContext context, IMapper mapper, IConfiguration configuration, ILogger<UserService> logger)
        {
            _context = context;
            _mapper = mapper;
            _idWorker = SnowflakeUtil.CreateIdWorker();
            _configuration = configuration;
            _logger = logger;
        }
        /// <summary>
        /// 激活用户
        /// </summary>
        /// <param name="activeCode">激活码</param>
        /// <returns></returns>
        public async Task<Results<string>> ActiveUserAsync(long activeCode)
        {
            var user = await _context.TabUsers.FirstOrDefaultAsync(c => c.ActiveCode == activeCode);
            if (user == null)
            {
                return Results<string>.FailResult("激活码无效");
            }
            //判断激活码是否过期
            if (CacheManager.Get<long>(string.Format(RedisKey.UserActiveCode, user.Id)) == 0L)
            {
                return Results<string>.FailResult("激活码无效");
            }
            user.ActiveStatus = true;
            await _context.SaveChangesAsync();
            CacheManager.Remove(string.Format(RedisKey.UserActiveCode, user.Id));
            return Results<string>.SuccessResult("用户激活成功");

        }

        /// <summary>
        /// 根据登录账号，发送授权码/验证码（用户可以拿着这个验证码去重置密码）
        /// </summary>
        /// <param name="loginAccount"></param>
        /// <returns></returns>
        public async Task<Results<int>> ForgetPwdAsync(string loginAccount)
        {
            Expression<Func<TabUser, bool>> expression = c => !c.Deleted && c.Username == loginAccount;

            if (FormatUtil.IsPhone(loginAccount))
            {
                expression = c => !c.Deleted && c.Mobile == loginAccount;
            }
            else if (FormatUtil.IsEmail(loginAccount))
            {
                expression = c => !c.Deleted && c.Email == loginAccount;
            }
            var user = await _context.TabUsers.AsNoTracking().FirstOrDefaultAsync(expression);
            if (user == null) { return Results<int>.FailResult("账号不存在"); }
            //验证码
            var authorizeCode = _idWorker.NextId();
            CacheManager.Set(string.Format(RedisKey.UserAuthorizeCode, user.Id), authorizeCode, TimeSpan.FromMinutes(5));
            EmailUtil.NetSendEmail($"请在找回密码页面中，输入登录账号（用户名/邮箱/手机）以及授权码用于修改密码<br />您的授权码是：" +
                               $"{authorizeCode},授权码30分钟有效"
            , "忘记密码？", user.Email);
            return Results<int>.SuccessResult("授权码已发送至您的注册邮箱，请尽快查收，授权码5分钟有效");

        }

        /// <summary>
        /// 登录(手机/邮箱/用户名)
        /// </summary>
        /// <param name="loginInput"></param>
        /// <returns></returns>
        public async Task<Results<UserDto>> LoginAsync(LoginInput loginInput)
        {
            var pwd = DesEncryptUtil.Md5Encrypt(loginInput.pwd);

            Expression<Func<TabUser, bool>> expression = c => !c.Deleted && c.Username == loginInput.LoginAccout && c.Password == pwd;

            if (FormatUtil.IsPhone(loginInput.LoginAccout))
            {
                expression = c => !c.Deleted && c.Mobile == loginInput.LoginAccout && c.Password == pwd;
            }
            else if (FormatUtil.IsEmail(loginInput.LoginAccout))
            {
                expression = c => !c.Deleted && c.Email == loginInput.LoginAccout && c.Password == pwd;
            }
            var user = await _context.TabUsers.AsNoTracking().Include(c => c.Role).FirstOrDefaultAsync(expression);
            if (user == null)
            {
                return Results<UserDto>.FailResult("用户名或密码错误");
            }
            if (!user.ActiveStatus)
            {
                return Results<UserDto>.FailResult("账号未激活");
            }
            return Results<UserDto>.DataResult(_mapper.Map<UserDto>(user));
        }
        /// <summary>
        /// 用户注册
        /// </summary>
        /// <param name="registerInput"></param>
        /// <returns></returns>
        public async Task<Results<UserDto>> RefisterAsync(RegisterInput registerInput)
        {
            if (!registerInput.Password.Equals(registerInput.ConfirmPwd))
            {
                return Results<UserDto>.FailResult("确认密码不一致");
            }
            if (registerInput.Password.Length < 6 || registerInput.Password.Length > 16)
            {
                return Results<UserDto>.FailResult("密码必须是6-16位");
            }
            //验重
            var check = CheckUser<UserDto>(registerInput.UserName, registerInput.Email, registerInput.Mobile);
            if (!check.Success)
            {
                return check;
            }
            var user = _mapper.Map<TabUser>(registerInput);
            long userId = _idWorker.NextId();
            user.Id = user.CreatedUserId = user.UpdatedUserId = userId;
            user.ActiveStatus = false;
            user.ActiveCode = _idWorker.NextId() >> 10;
            user.RoleId = (long)RoleEnum.User;
            user.Sex = 3;
            user.Password = DesEncryptUtil.Md5Encrypt(user.Password);
            user.Nickname = "";
            await _context.TabUsers.AddAsync(user);
            await _context.SaveChangesAsync();
            //设置激活码过期时间
            CacheManager.Set(string.Format(RedisKey.UserActiveCode, userId), user.ActiveCode, TimeSpan.FromDays(1));
            //发送邮箱
            EmailUtil.NetSendEmail($"欢迎注册旅途网，您的激活码是：{user.ActiveCode}<br/>激活码有效期至{DateTime.Now.AddDays(1)}", "旅途网账号激活", user.Email);
            return Results<UserDto>.GetResult(1, "注册成功，请尽快前往邮箱进行激活", _mapper.Map<UserDto>(user));
        }
        /// <summary>
        /// 修改个人资料
        /// </summary>
        /// <param name="userProfileInput"></param>
        /// <returns></returns>
        public async Task<Results<int>> UpdataUserProdileAsync(UserProfileInput userProfileInput)
        {
            var entity = await _context.TabUsers.FirstOrDefaultAsync(c => c.Username == userProfileInput.Username && !c.Deleted);
            if (entity == null)
            {
                return Results<int>.FailResult("未找到记录");
            }
            //验重
            var check = CheckUser<int>(userProfileInput.Username, userProfileInput.Email, userProfileInput.Mobile, entity.Id);
            if (!check.Success)
            {
                return check;
            }
            _mapper.Map(userProfileInput, entity);
            return Results<int>.DataResult(await _context.SaveChangesAsync());
        }

        /// <summary>
        /// 修改个人密码
        /// </summary>
        /// <param name="updatePwdInput"></param>
        /// <returns></returns>
        public async Task<Results<int>> UpdatePwdAsync(UpdatePwdInput updatePwdInput)
        {
            if (!updatePwdInput.NewPwd.Equals(updatePwdInput.CofirmNewPwd))
            {
                return Results<int>.FailResult("确认密码不一致");
            }
            var user = await _context.TabUsers.FirstOrDefaultAsync(c => c.Id == updatePwdInput.UserId);
            if (!user.Password.Equals(DesEncryptUtil.Md5Encrypt(updatePwdInput.OldPwd)))
            {
                return Results<int>.FailResult("旧密码错误");
            }
            user.Password = DesEncryptUtil.Md5Encrypt(updatePwdInput.NewPwd);
            return Results<int>.DataResult(await _context.SaveChangesAsync());
        }

        /// <summary>
        /// 找回密码
        /// </summary>
        /// <returns></returns>
        public async Task<Results<int>> UpdatePwdhenForgetAsync(UpdatePwdhenForgetInput input)
        {
            if (input.Password != input.ConfirmPassword)
            {
                return Results<int>.FailResult("密码不一致");
            }

            Expression<Func<TabUser, bool>> exp = c => !c.Deleted && c.Username == input.LoginAccount;
            if (FormatUtil.IsEmail(input.LoginAccount))
            {
                exp = c => !c.Deleted && c.Email == input.LoginAccount;
            }
            if (FormatUtil.IsPhone(input.LoginAccount))
            {
                exp = c => !c.Deleted && c.Mobile == input.LoginAccount;
            }
            var user = await _context.TabUsers.FirstOrDefaultAsync(exp);
            if (user == null)
            {
                return Results<int>.FailResult("账号输入有误");
            }
            var authorizeCode = CacheManager.Get<long>(string.Format(RedisKey.UserAuthorizeCode, user.Id));
            if (authorizeCode <= 0 || authorizeCode != input.AuthorizeCode)
            {
                return Results<int>.FailResult("验证码无效");
            }
            user.Password = DesEncryptUtil.Md5Encrypt(input.Password);
            return Results<int>.DataResult(await _context.SaveChangesAsync());
        }
        /// <summary>
        /// 用户分页查询
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<Results<PageDto<UserDto>>> UserQuery(UserQueryInput input)
        {
            var query = _context.TabUsers.Where(c => !c.Deleted && c.CreatedTime >= input.StartTime && c.CreatedTime <= input.EndTime);
            if (!string.IsNullOrWhiteSpace(input.Mobile))
            {
                query = query.Where(c => c.Mobile.StartsWith(input.Mobile));
            }
            if (!string.IsNullOrWhiteSpace(input.Username))
            {
                query = query.Where(c => c.Username.StartsWith(input.Username));
            }
            if (!string.IsNullOrWhiteSpace(input.Nickname))
            {
                query = query.Where(c => c.Nickname.Contains(input.Nickname));//NickName 非索引 所以可以使用Contains（因为Contains 是不会走索引）
            }
            if (!string.IsNullOrWhiteSpace(input.Email))
            {
                query = query.Where(c => c.Email.StartsWith(input.Email));
            }
            if (input.RoleId.HasValue && input.RoleId > 0)
            {
                query = query.Where(c => c.RoleId == input.RoleId);
            }
            PageDto<UserDto> pageDto = new PageDto<UserDto>();
            pageDto.Total = query.Count();
            List<TabUser> list = query.OrderByDescending(c => c.CreatedTime).Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToList();
            pageDto.Data = _mapper.Map<List<UserDto>>(list);
            return Results<PageDto<UserDto>>.DataResult(pageDto);
        }

        /// <summary>
        /// 验重
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="userName"></param>
        /// <param name="email"></param>
        /// <param name="mobile"></param>
        /// <returns></returns>
        private Results<T> CheckUser<T>(string userName, string email, string mobile, long userId = 0)
        {
            if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(mobile))
            {
                return Results<T>.InValidParameter();
            }

            if (!FormatUtil.IsPhone(mobile))
            {
                return Results<T>.FailResult("手机格式不正确");
            }
            if (!FormatUtil.IsEmail(email))
            {
                return Results<T>.FailResult("手机格式不正确");
            }
            if (_context.TabUsers.Count(c => !c.Deleted && c.Username == userName && c.Id != userId) > 0)
            {
                return Results<T>.FailResult("用户名已被注册");
            }
            if (_context.TabUsers.Count(c => !c.Deleted && c.Email == email && c.Id != userId) > 0)
            {
                return Results<T>.FailResult("邮箱已被注册");
            }
            if (_context.TabUsers.Count(c => !c.Deleted && c.Mobile == mobile && c.Id != userId) > 0)
            {
                return Results<T>.FailResult("手机号已被注册");
            }
            return Results<T>.SuccessResult();
        }
        /// <summary>
        /// 根据用户ID获取一条数据
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<Results<UserDto>> GetUserByIdAsync(long userId)
        {
            var user = await _context.TabUsers.AsNoTracking().Include(c => c.Role).FirstOrDefaultAsync(c => !c.Deleted && c.Id == userId);
            if (user == null)
            {

                return Results<UserDto>.FailResult("未找到该用户");
            }
            return Results<UserDto>.DataResult(_mapper.Map<UserDto>(user));
        }
        /// <summary>
        /// 根据用户ID删除一条数据
        /// </summary>
        /// <param name="userId">要删除的用户ID</param>
        /// <param name="loginUserId">当前登录人</param>
        /// <returns></returns>
        public async Task<Results<int>> DeleteUserByIdAsync(long userId, long loginUserId)
        {
            var user = await _context.TabUsers.FirstOrDefaultAsync(c => !c.Deleted && c.Id == userId);
            if (user == null)
            {
                return Results<int>.FailResult("未找到该用户");
            }
            user.Deleted = true;
            user.UpdatedUserId = loginUserId;
            return Results<int>.DataResult(await _context.SaveChangesAsync());
        }
        /// <summary>
        /// 添加或者修改用户信息（管理员操作）
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<Results<int>> AddOrUpdataAsync(UserAddOrUpdataInput input)
        {
            var check = CheckUser<int>(input.Username, input.Email, input.Mobile, input.Id);
            if (!check.Success)
            {
                return check;
            }
            if (input.Id > 0)
            {
                var entity = await _context.TabUsers.FirstOrDefaultAsync(c => !c.Deleted && c.Id == input.Id);
                if (entity == null)
                {
                    return Results<int>.FailResult("找不到指定用户");
                }
                _mapper.Map(input, entity);
            }
            else
            {
                var userId = _idWorker.NextId();
                var tabUser = _mapper.Map<TabUser>(input);
                tabUser.Id = userId;
                tabUser.ActiveCode = userId >> 10;
                tabUser.ActiveStatus = true;
                tabUser.Password = DesEncryptUtil.Md5Encrypt("123456");
                await _context.AddAsync(tabUser);
            }
            return Results<int>.DataResult(await _context.SaveChangesAsync());
        }
        /// <summary>
        /// 批量导入用户
        /// </summary>
        /// <param name=""></param>
        /// <param name="loginUserId"></param>
        /// <returns></returns>
        public async Task<Results<int>> ImportUser(List<TravelUserDto> list, long loginUserId)
        {
            var opt = new DbContextOptionsBuilder<HappyTravelContext>();
            opt.UseMySql(_configuration.GetConnectionString("mysql"), new MySqlServerVersion("7.0"));
            await using var context = new HappyTravelContext(opt.Options);
            int success = 0;

            var userNameList = context.TabUsers.AsNoTracking().Where(c=>list.Select(c=>c.Username).Contains(c.Username)).Select(c=>c.Username);
            if (userNameList.Any())
            {
                list.RemoveAll(c=>userNameList.Contains(c.Username));
            }

            var userEmialList = context.TabUsers.AsNoTracking().Where(c => list.Select(c => c.Email).Contains(c.Email)).Select(c => c.Email);
            if (userEmialList.Any())
            {
                list.RemoveAll(c => userEmialList.Contains(c.Email));
            }

            var userModileList = context.TabUsers.AsNoTracking().Where(c => list.Select(c => c.Mobile).Contains(c.Mobile)).Select(c => c.Mobile);
            if (userModileList.Any())
            {
                list.RemoveAll(c => userModileList.Contains(c.Mobile));
            }
            foreach (var item in list)
            {
                TabUser tabUser = ObjectMapper.Map<TabUser>(item);
                tabUser.Sex = 3;
                tabUser.Password = DesEncryptUtil.Md5Encrypt("123456");
                tabUser.RoleId = ((int)RoleEnum.User);
                tabUser.ActiveStatus = true;
                tabUser.Id = SnowIdWorker.NextId();
                tabUser.ActiveCode = tabUser.Id;
                tabUser.CreatedUserId = tabUser.UpdatedUserId = loginUserId;
               await context.TabUsers.AddAsync(tabUser);
            }
            try
            {
                success += await context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
            }
            return Results<int>.DataResult(success);
        }
    }
}
